package bancosys.tec.utils.db.executor;

import java.net.URL;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.dbcp.BasicDataSource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * @author Marcio Ribeiro (mmr)
 * @created Apr 25, 2007
 */
public abstract class AbstractDbExecutor implements DbExecutor {

    protected static final Log LOG = LogFactory.getLog(AbstractDbExecutor.class);

    public static final String DEFAULT_SCRIPT_PATTERN = ".*\\.[Ss][Qq][Ll]$";

    private BasicDataSource dataSource;

    private Connection connection;

    private String scriptPattern = DEFAULT_SCRIPT_PATTERN;

    private boolean toUpper;

    private URL file;

    private Map<String, String> parameters;

    /**
     * Devolve o arquivo.
     * 
     * @return o arquivo.
     */
    public URL getFile() {
        return this.file;
    }

    /**
     * Devolve a conexão.
     * 
     * @return a conexão.
     * @throws SQLException Se não for possível recuperar uma conexão
     */
    public Connection getConnection() throws SQLException {
        if (this.connection == null) {
            if (this.dataSource == null) {
                // de duas uma, ou este executor foi configurado via construtor e eu
                // já tenho uma conexão ou foi configurado via configure e o dataSource
                // está setado. Se cair aqui, o estado do executor está inválido.
                throw new IllegalStateException("Executor mal configurado! Forneça o data source!");
            }
            this.connection = this.dataSource.getConnection();
        }
        return this.connection;
    }

    /**
     * Devolve o pattern p/ nome do arquivo.
     * 
     * @return o pattern p/ nome do arquivo.
     */
    public String getScriptPattern() {
        return this.scriptPattern;
    }

    /**
     * Define o pattern p/ nome do arquivo.
     * 
     * @param scriptPattern o pattern p/ nome do arquivo.
     */
    public void setScriptPattern(String scriptPattern) {
        this.scriptPattern = scriptPattern;
    }

    /**
     * @return <code>true</code> se deve forcar queries para upper antes de executa-las.
     */
    public boolean getToUpper() {
        return this.toUpper;
    }

    /**
     * Define se deve forcar queries para upper antes de executa-las.
     * 
     * @param toUpper <code>true</code> se sim, <code>false</code> se nao.
     */
    public void setToUpper(boolean toUpper) {
        this.toUpper = toUpper;
    }

    /**
     * Executa o script.
     * 
     * @throws CouldNotExecuteException quando ocorre erro na execução do script.
     */
    public final void execute() throws CouldNotExecuteException {
        this.execute(false);
    }

    /**
     * Configura este executor. Informa qual foi o dataSource especificado e o arquivo com o script de criação do BD.
     * 
     * @param dataSrc O DataSource
     * @param schemaFile O arquivo de schema
     */
    public void configure(BasicDataSource dataSrc, URL schemaFile) {
        this.configure(dataSrc, schemaFile, new HashMap<String, String>());
    }

    /**
     * Configura este executor. Informa qual foi o dataSource especificado, o arquivo com o script de criação do BD e o mapa de parâmetros
     * fornecidos.
     * 
     * @param dataSrc O DataSource
     * @param schemaFile O arquivo de schema
     * @param param O mapa de parâmetros
     */
    public void configure(BasicDataSource dataSrc, URL schemaFile, Map<String, String> param) {
        this.dataSource = dataSrc;
        this.file = schemaFile;
        this.parameters = param;
    }

    /**
     * Configura este executor. Informa qual conexão utilizar e o arquivo com o script de criação do BD.
     * 
     * @param conn A conexão
     * @param schemaFile O arquivo de schema
     */
    public void configure(Connection conn, URL schemaFile) {
        this.configure(conn, schemaFile, new HashMap<String, String>());
    }

    /**
     * Configura este executor. Informa qual conexão utilizar, o arquivo com o script de criação do BD e o mapa de parâmetros fornecidos.
     * 
     * @param conn A conexão
     * @param schemaFile O arquivo de schema
     * @param param O mapa de parâmetros
     */
    public void configure(Connection conn, URL schemaFile, Map<String, String> param) {
        this.connection = conn;
        this.file = schemaFile;
        this.parameters = param;
    }

    /**
     * Obtém o parâmetro, retornando o valor default caso não tenha sido encontrado.
     * 
     * @param key key
     * @param defaultValue defaultValue
     * @return String
     */
    protected String getParameter(String key, String defaultValue) {
        if (this.parameters.containsKey(key)) {
            return this.parameters.get(key);
        } else {
            return defaultValue;
        }
    }

}
